Trò chơi Tic-Tac-Toe, game đánh caro full source code
- PhotonHandler.cs
- PhotonNetwork /
- Plugins /
- Photon Unity Networking /
- Assets /
- project /
2 // <copyright file="PhotonHandler.cs" company="Exit Games GmbH">
3 // Part of: Photon Unity Networking
4 // </copyright>
5 // --------------------------------------------------------------------------------------------------------------------
6
7 using System;
8 using System.Collections;
9 using ExitGames.Client.Photon;
10 using UnityEngine;
11
12 using Hashtable = ExitGames.Client.Photon.Hashtable;
13
14
15 /// <summary>
16 /// Internal Monobehaviour that allows Photon to run an Update loop.
17 /// </summary>
18 internal class PhotonHandler : Photon.MonoBehaviour, IPhotonPeerListener
19 {
20 public static PhotonHandler SP;
21
22 public int updateInterval; // time [ms] between consecutive SendOutgoingCommands calls
23
24 public int updateIntervalOnSerialize; // time [ms] between consecutive RunViewUpdate calls (sending syncs, etc)
25
26 private int nextSendTickCount = 0;
27
28 private int nextSendTickCountOnSerialize = 0;
29
30 private static bool sendThreadShouldRun;
31 public static bool AppQuits;
32
33 public static Type PingImplementation = null;
34
35 protected void Awake()
36 {
37 if (SP != null && SP != this && SP.gameObject != null)
38 {
39 GameObject.DestroyImmediate(SP.gameObject);
40 }
41
42 SP = this;
43 DontDestroyOnLoad(this.gameObject);
44
45 this.updateInterval = 1000 / PhotonNetwork.sendRate;
46 this.updateIntervalOnSerialize = 1000 / PhotonNetwork.sendRateOnSerialize;
47
48 PhotonHandler.StartFallbackSendAckThread();
49 }
50
51 /// <summary>Called by Unity when the application is closed. Tries to disconnect.</summary>
52 protected void OnApplicationQuit()
53 {
54 PhotonHandler.AppQuits = true;
55 PhotonHandler.StopFallbackSendAckThread();
56 PhotonNetwork.Disconnect();
57 }
58
59 protected void Update()
60 {
61 if (PhotonNetwork.networkingPeer == null)
62 {
63 Debug.LogError("NetworkPeer broke!");
64 return;
65 }
66
67 if (PhotonNetwork.connectionStateDetailed == PeerState.PeerCreated || PhotonNetwork.connectionStateDetailed == PeerState.Disconnected || PhotonNetwork.offlineMode)
68 {
69 return;
70 }
71
72 // the messageQueue might be paused. in that case a thread will send acknowledgements only. nothing else to do here.
73 if (!PhotonNetwork.isMessageQueueRunning)
74 {
75 return;
76 }
77
78 bool doDispatch = true;
79 while (PhotonNetwork.isMessageQueueRunning && doDispatch)
80 {
81 // DispatchIncomingCommands() returns true of it found any command to dispatch (event, result or state change)
82 UnityEngine.Profiling.Profiler.BeginSample("DispatchIncomingCommands");
83 doDispatch = PhotonNetwork.networkingPeer.DispatchIncomingCommands();
84 UnityEngine.Profiling.Profiler.EndSample();
85 }
86
87 int currentMsSinceStart = (int)(Time.realtimeSinceStartup * 1000); // avoiding Environment.TickCount, which could be negative on long-running platforms
88 if (PhotonNetwork.isMessageQueueRunning && currentMsSinceStart > this.nextSendTickCountOnSerialize)
89 {
90 PhotonNetwork.networkingPeer.RunViewUpdate();
91 this.nextSendTickCountOnSerialize = currentMsSinceStart + this.updateIntervalOnSerialize;
92 this.nextSendTickCount = 0; // immediately send when synchronization code was running
93 }
94
95 currentMsSinceStart = (int)(Time.realtimeSinceStartup * 1000);
96 if (currentMsSinceStart > this.nextSendTickCount)
97 {
98 bool doSend = true;
99 while (PhotonNetwork.isMessageQueueRunning && doSend)
100 {
101 // Send all outgoing commands
102 UnityEngine.Profiling.Profiler.BeginSample("SendOutgoingCommands");
103 doSend = PhotonNetwork.networkingPeer.SendOutgoingCommands();
104 UnityEngine.Profiling.Profiler.EndSample();
105 }
106
107 this.nextSendTickCount = currentMsSinceStart + this.updateInterval;
108 }
109 }
110
111 /// <summary>Called by Unity after a new level was loaded.</summary>
112 protected void OnLevelWasLoaded(int level)
113 {
114 PhotonNetwork.networkingPeer.NewSceneLoaded();
115 PhotonNetwork.networkingPeer.SetLevelInPropsIfSynced(Application.loadedLevelName);
116 }
117
118 protected void OnJoinedRoom()
119 {
120 PhotonNetwork.networkingPeer.LoadLevelIfSynced();
121 }
122
123 protected void OnCreatedRoom()
124 {
125 PhotonNetwork.networkingPeer.SetLevelInPropsIfSynced(Application.loadedLevelName);
126 }
127
128 public static void StartFallbackSendAckThread()
129 {
130 if (sendThreadShouldRun)
131 {
132 return;
133 }
134
135 sendThreadShouldRun = true;
136 SupportClass.CallInBackground(FallbackSendAckThread); // thread will call this every 100ms until method returns false
137 }
138
139 public static void StopFallbackSendAckThread()
140 {
141 sendThreadShouldRun = false;
142 }
143
144 public static bool FallbackSendAckThread()
145 {
146 if (sendThreadShouldRun && PhotonNetwork.networkingPeer != null)
147 {
148 PhotonNetwork.networkingPeer.SendAcksOnly();
149 }
150
151 return sendThreadShouldRun;
152 }
153
154 #region Implementation of IPhotonPeerListener
155
156 public void DebugReturn(DebugLevel level, string message)
157 {
158 if (level == DebugLevel.ERROR)
159 {
160 Debug.LogError(message);
161 }
162 else if (level == DebugLevel.WARNING)
163 {
164 Debug.LogWarning(message);
165 }
166 else if (level == DebugLevel.INFO && PhotonNetwork.logLevel >= PhotonLogLevel.Informational)
167 {
168 Debug.Log(message);
169 }
170 else if (level == DebugLevel.ALL && PhotonNetwork.logLevel == PhotonLogLevel.Full)
171 {
172 Debug.Log(message);
173 }
174 }
175
176 public void OnOperationResponse(OperationResponse operationResponse)
177 {
178 }
179
180 public void OnStatusChanged(StatusCode statusCode)
181 {
182 }
183
184 public void OnEvent(EventData photonEvent)
185 {
186 }
187
188 #endregion
189
190
191
192 #region Photon Cloud Ping Evaluation
193
194
195 private const string PlayerPrefsKey = "PUNCloudBestRegion";
196
197 internal static CloudRegionCode BestRegionCodeCurrently = CloudRegionCode.none; // default to none
198 internal static CloudRegionCode BestRegionCodeInPreferences
199 {
200 get
201 {
202 string prefsRegionCode = PlayerPrefs.GetString(PlayerPrefsKey, "");
203 if (!string.IsNullOrEmpty(prefsRegionCode))
204 {
205 CloudRegionCode loadedRegion = Region.Parse(prefsRegionCode);
206 return loadedRegion;
207 }
208
209 return CloudRegionCode.none;
210 }
211 set
212 {
213 if (value == CloudRegionCode.none)
214 {
215 PlayerPrefs.DeleteKey(PlayerPrefsKey);
216 }
217 else
218 {
219 PlayerPrefs.SetString(PlayerPrefsKey, value.ToString());
220 }
221 }
222 }
223
224
225
226 internal protected static void PingAvailableRegionsAndConnectToBest()
227 {
228 SP.StartCoroutine(SP.PingAvailableRegionsCoroutine(true));
229 }
230
231
232 internal IEnumerator PingAvailableRegionsCoroutine(bool connectToBest)
233 {
234 BestRegionCodeCurrently = CloudRegionCode.none;
235 while (PhotonNetwork.networkingPeer.AvailableRegions == null)
236 {
237 if (PhotonNetwork.connectionStateDetailed != PeerState.ConnectingToNameServer && PhotonNetwork.connectionStateDetailed != PeerState.ConnectedToNameServer)
238 {
239 Debug.LogError("Call ConnectToNameServer to ping available regions.");
240 yield break; // break if we don't connect to the nameserver at all
241 }
242
243 Debug.Log("Waiting for AvailableRegions. State: " + PhotonNetwork.connectionStateDetailed + " Server: " + PhotonNetwork.Server + " PhotonNetwork.networkingPeer.AvailableRegions " + (PhotonNetwork.networkingPeer.AvailableRegions != null));
244 yield return new WaitForSeconds(0.25f); // wait until pinging finished (offline mode won't ping)
245 }
246
247 if (PhotonNetwork.networkingPeer.AvailableRegions == null || PhotonNetwork.networkingPeer.AvailableRegions.Count == 0)
248 {
249 Debug.LogError("No regions available. Are you sure your appid is valid and setup?");
250 yield break; // break if we don't get regions at all
251 }
252
253 //#if !UNITY_EDITOR && (UNITY_ANDROID || UNITY_IPHONE)
254 //#pragma warning disable 0162 // the library variant defines if we should use PUN's SocketUdp variant (at all)
255 //if (PhotonPeer.NoSocket)
256 //{
257 // if (PhotonNetwork.logLevel >= PhotonLogLevel.Informational)
258 // {
259 // Debug.Log("PUN disconnects to re-use native sockets for pining servers and to find the best.");
260 // }
261 // PhotonNetwork.Disconnect();
262 //}
263 //#pragma warning restore 0162
264 //#endif
265
266 PhotonPingManager pingManager = new PhotonPingManager();
267 foreach (Region region in PhotonNetwork.networkingPeer.AvailableRegions)
268 {
269 SP.StartCoroutine(pingManager.PingSocket(region));
270 }
271
272 while (!pingManager.Done)
273 {
274 yield return new WaitForSeconds(0.1f); // wait until pinging finished (offline mode won't ping)
275 }
276
277
278 Region best = pingManager.BestRegion;
279 PhotonHandler.BestRegionCodeCurrently = best.Code;
280 PhotonHandler.BestRegionCodeInPreferences = best.Code;
281
282 Debug.Log("Found best region: " + best.Code + " ping: " + best.Ping + ". Calling ConnectToRegionMaster() is: " + connectToBest);
283
284
285 if (connectToBest)
286 {
287 PhotonNetwork.networkingPeer.ConnectToRegionMaster(best.Code);
288 }
289 }
290
291
292
293 #endregion
294
295 }
--------------------------------------------------------------------------------------------------------------------
Part of: Photon Unity Networking
--------------------------------------------------------------------------------------------------------------------
Internal Monobehaviour that allows Photon to run an Update loop.
public int updateInterval; time [ms] between consecutive SendOutgoingCommands calls
public int updateIntervalOnSerialize; time [ms] between consecutive RunViewUpdate calls (sending syncs, etc)
the messageQueue might be paused. in that case a thread will send acknowledgements only. nothing else to do here.
DispatchIncomingCommands() returns true of it found any command to dispatch (event, result or state change)
int currentMsSinceStart = (int)(Time.realtimeSinceStartup * 1000); avoiding Environment.TickCount, which could be negative on long-running platforms
this.nextSendTickCount = 0; immediately send when synchronization code was running
Send all outgoing commands
SupportClass.CallInBackground(FallbackSendAckThread); thread will call this every 100ms until method returns false
internal static CloudRegionCode BestRegionCodeCurrently = CloudRegionCode.none; default to none
yield break; break if we don't connect to the nameserver at all
yield return new WaitForSeconds(0.25f); wait until pinging finished (offline mode won't ping)
yield break; break if we don't get regions at all
#if !UNITY_EDITOR && (UNITY_ANDROID || UNITY_IPHONE)
#pragma warning disable 0162 the library variant defines if we should use PUN's SocketUdp variant (at all)
if (PhotonPeer.NoSocket)
{
if (PhotonNetwork.logLevel >= PhotonLogLevel.Informational)
{
Debug.Log("PUN disconnects to re-use native sockets for pining servers and to find the best.");
}
PhotonNetwork.Disconnect();
}
#pragma warning restore 0162
#endif
yield return new WaitForSeconds(0.1f); wait until pinging finished (offline mode won't ping)